<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Painting II in Mono Winforms</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="Mono, IronPython, painting, Winforms, tutorial, programming">
<meta name="description" content="Painting II in Mono Winforms">
<meta name="language" content="en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

</head>

<body>

<div class="container">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<div class="content">


<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>Painting II in Mono Winforms</h1>


<p>
In this part of the IronPython Mono Winforms tutorial, we will continue with painting. 
</p>

<div class="center">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<h2>Donut</h2>

<p>
In the following example we create an complex shape by rotating a bunch of ellipses. 
</p>

<div class="codehead">donut.py</div>
<pre class="code">
#!/usr/bin/ipy

import clr

clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")

from System.Windows.Forms import Application, Form
from System.Drawing import Size, Color, SolidBrush, Pen

class IForm(Form):

    def __init__(self):
        self.Text = 'Donut'
        self.Size = Size(350, 300)

        self.Paint += self.OnPaint
        self.CenterToScreen()

    def OnPaint(self, event):

        g = event.Graphics
        pen = Pen(Color.Gray, 1)
        
        size = self.ClientSize
        g.TranslateTransform(size.Width/2, size.Height/2)
        g.DrawEllipse(pen, -125, -125, 250, 250)
        
        for i in range(0, 36):
            g.DrawEllipse(pen, 0, 0, 120, 50)
            g.RotateTransform(10)
            
        g.Dispose()

Application.Run(IForm())
</pre>


<p>
We draw five lines on the form. Each line has different <b class="keyword">DashStyle</b>.  
</p>


<pre class="explanation">
 size = self.ClientSize
 g.TranslateTransform(size.Width/2, size.Height/2)
 g.DrawEllipse(pen, -125, -125, 250, 250)
</pre>

<p>
We draw a circle in the middle of the form. 
</p>

<pre class="explanation">
 for i in range(0, 36):
     g.DrawEllipse(pen, 0, 0, 120, 50)
     g.RotateTransform(10)
</pre>

<p>
We draw 36 ellipses, each rotated by 10 degree after the last one.
Thus getting the donut object. 
</p>


<br>
<img src="/img/gui/ironpython/donut.png" alt="Donut">
<div class="figure">Figure: Donut</div>


<h2>Transparent rectangles</h2>

<p>
Transparency is the quality of being able to see through a material. The easiest 
way to understand transparency is to imagine a piece of glass or water. Technically, 
the rays of light can go through the glass and this way we can see objects behind the glass.
</p>
<p>
In computer graphics, we can achieve transparency effects using alpha compositing. 
Alpha compositing is the process of combining an image with a background to create 
the appearance of partial transparency. The composition process uses an alpha 
channel. (wikipedia.org, answers.com) 
</p>

<div class="codehead">transparentrectangles.py</div>
<pre class="code">
#!/usr/bin/ipy

import clr

clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")

from System.Windows.Forms import Application, Form
from System.Drawing import Size, Color, SolidBrush

class IForm(Form):

    def __init__(self):
        self.Text = 'Transparent rectangles'
        self.Size = Size(590, 110)

        self.Paint += self.OnPaint
        
        self.CenterToScreen()


    def OnPaint(self, event):

        g = event.Graphics

        for i in range(1, 11):
            color = Color.FromArgb(i*25, 0, 0, 255)
            brush = SolidBrush(color)
            g.FillRectangle(brush, 50*i, 20, 40, 40)
            

Application.Run(IForm())
</pre>

<p>
In the example we will draw ten rectangles with different levels of transparency. 
</p>

<pre class="explanation">
 color = Color.FromArgb(i*25, 0, 0, 255)
</pre>

<p>
This line creates a color object. The first value is the alpha transparency. 
</p>

<pre class="explanation">
 brush = SolidBrush(color)
</pre>

<p>
We create a brush from the color. 
</p>

<pre class="explanation">
 g.FillRectangle(brush, 50*i, 20, 40, 40)
</pre>

<p>
We draw a rectangle.  
</p>

<br>
<img src="/img/gui/ironpython/transparency.png" alt="Transparent rectangles">
<div class="figure">Figure: Transparent rectangles</div>


<h2>Grayscale image</h2>

<p>
The following example creates a grayscale image. 
</p>

<div class="codehead">grayscale.py</div>
<pre class="code">
#!/usr/bin/ipy

import clr
import sys

clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")

from System.Windows.Forms import Application, Form
from System.Drawing import Size, Rectangle
from System.Drawing import Bitmap, Color

class IForm(Form):

    def __init__(self):
        self.Text = 'Grayscale'
        self.Size = Size(290, 150)

        self.Paint += self.OnPaint

        self.rotunda = self.loadImage()
        self.gs = self.grayScale(self.rotunda.Clone())

        self.CenterToScreen()

    def loadImage(self):
        try:
            rotunda = Bitmap("rotunda.jpg")
            return rotunda
        except Exception, e:
            print e.msg
            sys.exit(1)

    def grayScale(self, image):
        
        w = image.Width
        h = image.Height

        for i in range(w):
            for j in range(h):
                c = image.GetPixel(i, j)
                lum = 0.299*c.R + 0.587*c.G + 0.114*c.B
                image.SetPixel(i, j, Color.FromArgb(lum, lum, lum))
          
        return image


    def OnPaint(self, event):

        g = event.Graphics

        r1 = Rectangle(15, 15, self.rotunda.Width, self.rotunda.Height)
        g.DrawImage(self.rotunda, r1)

        r2 = Rectangle(150, 15, self.gs.Width, self.gs.Height)
        g.DrawImage(self.gs, r2)
        
        g.Dispose()

Application.Run(IForm())
</pre>


<p>
We have two images in our example. A color and a grayscale one. 
</p>


<pre class="explanation">
 self.rotunda = self.loadImage()
</pre>

<p>
The <b class="keyword">loadImage()</b> method loads a bitmap
from the current working directory of the disk. 
</p>

<pre class="explanation">
 self.gs = self.grayScale(self.rotunda.Clone())
</pre>

<p>
The <b class="keyword">grayScale()</b> method makes a grayscale image from
a color image. We give a copy of the rotunda image as a parameter to 
this method. 
</p>

<pre class="explanation">
 c = image.GetPixel(i, j)
</pre>

<p>
We get all pixels from the image. 
</p>

<pre class="explanation">
 lum = 0.299*c.R + 0.587*c.G + 0.114*c.B
</pre>

<p>
This equation calculates a luminocity for a grayscale image. If we scale 
the the red, green and blue parts of 
the color with these factors, the human eye sees the image as gray.
</p>

<pre class="explanation">
 image.SetPixel(i, j, Color.FromArgb(lum, lum, lum))
</pre>

<p>
We modify the pixel.
</p>

<br>
<img src="/img/gui/ironpython/grayscale.png" alt="Grayscale image">
<div class="figure">Figure: Grayscale image</div>


<h2>Gradients</h2>

<p>
In computer graphics, gradient is a smooth blending of shades from light to dark 
or from one color to another. In 2D drawing programs and paint programs, 
gradients are used to create colorful backgrounds and special effects
as well as to simulate lights and shadows. (answers.com) 
</p>

<div class="codehead">gradients.py</div>
<pre class="code">
#!/usr/bin/ipy

import clr

clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")

from System.Windows.Forms import Application, Form
from System.Drawing import Size, Color, Point
from System.Drawing.Drawing2D import LinearGradientBrush

class IForm(Form):

    def __init__(self):
        self.Text = 'Gradients'
        self.Size = Size(350, 350)
        self.Paint += self.OnPaint

        self.CenterToScreen()

    def OnPaint(self, event):

        g = event.Graphics

        pt1 = Point(5, 5)
        pt2 = Point(25, 25)
        lg =  LinearGradientBrush(pt1, pt2, Color.Red, Color.Black)
        g.FillRectangle(lg, 20, 20, 300, 40)

        pt1 = Point(5, 25)
        pt2 = Point(20, 2)
        lg = LinearGradientBrush(pt1, pt2, Color.Yellow, Color.Black)
        g.FillRectangle(lg, 20, 80, 300, 40)

        pt1 = Point(5, 25)
        pt2 = Point(2, 2)
        lg = LinearGradientBrush(pt1, pt2, Color.Green, Color.Black)
        g.FillRectangle(lg, 20, 140, 300, 40)

        pt1 = Point(25, 25)
        pt2 = Point(15, 25)
        lg =  LinearGradientBrush(pt1, pt2, Color.Blue, Color.Black)
        g.FillRectangle(lg, 20, 200, 300, 40)

        pt1 = Point(0, 10)
        pt2 = Point(0, 20)
        lg = LinearGradientBrush(pt1, pt2, Color.Orange, Color.Black)
        g.FillRectangle(lg, 20, 260, 300, 40)

        lg.Dispose()
        g.Dispose()


Application.Run(IForm())
</pre>

<p>
We draw five rectangles which are filled with different linear gradients. 
</p>

<pre class="explanation">
 pt1 = Point(5, 5)
 pt2 = Point(25, 25)
</pre>

<p>
These two are the controlling points of the linear gradient brush. 
</p>

<pre class="explanation">
 lg =  LinearGradientBrush(pt1, pt2, Color.Red, Color.Black)
</pre>

<p>
We create the <b class="keyword">LinearGradientBrush</b> object. We use two controlling points and
two blending colors. 
</p>

<br>
<img src="/img/gui/ironpython/gradients.png" alt="Gradients">
<div class="figure">Figure: Gradients</div>



<h2>Waiting</h2>

<p>
In this examle, we use transparency effect to create a waiting demo.
We will draw 8 lines that will gradually fade out creating an illusion, 
that a line is moving. Such effects are often used to inform users, 
that a lengthy task is going on behind the scenes. 
An example is streaming video over the internet. 
</p>

<div class="codehead">waiting.py</div>
<pre class="code">
#!/usr/bin/ipy

import clr

clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")

from System.Windows.Forms import Application, Form, Timer
from System.Drawing import Size, Color, SolidBrush, Pen
from System.Drawing.Drawing2D import SmoothingMode, LineCap
from System.ComponentModel import Container


trs =  (
    ( 0, 35, 70, 100, 150, 180, 210, 250 ),
    ( 250, 0, 35, 70, 100, 150, 180, 210  ),
    ( 210, 250, 0, 35, 70, 100, 150, 180  ),
    ( 180, 210, 250, 0, 35, 70, 100, 150 ),
    ( 150, 180, 210, 250, 0, 35, 70, 100 ),
    ( 100, 150, 180, 210, 250, 0, 35, 70 ),
    ( 70, 100, 150, 180, 210, 250, 0, 35 ),
    ( 35, 70, 100, 150, 180, 210, 250, 0 )
)


class IForm(Form):

    def __init__(self):
        self.Text = 'Waiting'
        self.Size = Size(250, 150)

        self.Paint += self.OnPaint

        self.count = 0
        
        self.timer = Timer(Container())
        self.timer.Enabled = True
        self.timer.Interval = 80
        self.timer.Tick += self.OnTick

        self.CenterToScreen()

    
    def OnTick(self, sender, event):
        self.count = self.count + 1
        self.Refresh()

    def OnPaint(self, event):

        g = event.Graphics
        g.SmoothingMode = SmoothingMode.AntiAlias
        
        size = self.ClientSize
        g.TranslateTransform(size.Width/2, size.Height/2)
        
        for i in range(0, 8):
            color = Color.FromArgb(trs[self.count%8][i], 30, 30, 30)
            pen = Pen(color, 3)
            pen.StartCap = LineCap.Round
            pen.EndCap = LineCap.Round
            g.DrawLine(pen, 0, -10, 0, -40)
            g.RotateTransform(45)
            
        pen.Dispose()    
        g.Dispose()
        

Application.Run(IForm())
</pre>

<p>
 We draw eight lines with eight different alpha values. 
</p>

<pre class="explanation">
 self.timer = Timer(Container())
 self.timer.Enabled = True
 self.timer.Interval = 80
 self.timer.Tick += self.On
</pre>

<p>
We use <b class="keyword">Timer</b> to create animation.
</p>

<pre class="explanation">
trs =  (
    ( 0, 35, 70, 100, 150, 180, 210, 250 ),
    ...
)
</pre>

<p>
This is a two dimensional collectino of transparency values used in this demo. 
There are 8 rows, each for one state. Each of the 8 lines will continuosly use these values. 
</p>

<pre class="explanation">
 pen = Pen(color, 3)
 pen.StartCap = LineCap.Round
 pen.EndCap = LineCap.Round
</pre>

<p>
We make the lines a bit thicker, so that they are better visible. 
We draw the lines with rouded caps. 
</p>

<pre class="explanation">
 color = Color.FromArgb(trs[self.count%8][i], 30, 30, 30)
</pre>

<p>
Here we define the transparency value for a line. 
</p>

<pre class="explanation">
 g.DrawLine(pen, 0, -10, 0, -40)
 g.RotateTransform(45)
</pre>

<p>
We draw 8 lines. They are roteted clockwise. 
</p>

<br>
<img src="/img/gui/ironpython/waiting.png" alt="Waiting">
<div class="figure">Figure: Waiting</div>

<hr class="btm">

<p>
In this chapter of the IronPython Winforms tutorial,
we did some more advanced painting in Mono Winforms library.  
</p>

<div class="center">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>
<br>


<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡ 
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified January 30, 2009  <span class="copyright">&copy; 2007 - 2011 Jan Bodnar</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->

</body>
</html>

